package com.ys.xml;

import com.ys.bean.support.*;
import com.ys.enumeration.BeanScope;
import com.ys.exception.BeanDefinitionStoreException;
import com.ys.io.Resource;
import com.ys.io.UrlResource;
import com.ys.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;

/**
 * <p>@description:xml配置文件的加载操作</p>
 *
 * @projectName: Spring-Mini
 * @packageName: com.com.ys.xml
 * @className:
 * @author: shuangyang
 * @date: 1/15/17 2:50 PM
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    private static Logger logger = LoggerFactory.getLogger(XmlBeanDefinitionReader.class);

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    /**
     * Load bean definitions from the specified xml file.
     *
     * @param resource
     * @return
     * @throws BeanDefinitionStoreException
     */
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        try {
            UrlResource urlResource = (UrlResource) resource;
            return doLoadBeanDefinitions(urlResource.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 处理beanDefinitions的加载操作
     * Actually load bean definitions from the specified xml file
     *
     * @param inputStream
     */
    protected int doLoadBeanDefinitions(InputStream inputStream) throws BeanDefinitionStoreException {
        try {
           /*创建文档读取器*/
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //解析输入流中的文件
            Document doc = documentBuilder.parse(inputStream);
            //解析bean并注册
            return registerBeanDefinitions(doc);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 通过配置文件解析并注入Bean definitions
     * Register the bean defintions containec in the given DOM document
     *
     * @param doc
     */
    public int registerBeanDefinitions(Document doc) {
        logger.debug("loading bean definitioons");
        //获取文档种的元素
        Element root = doc.getDocumentElement();
        /*解析之前已存在的bean的数量*/
     /*   int countBefore = getRegistry().getBeanDefinitionCount();*/
        //执行解析操作 //TODO
        return doRegisterBeanDefinitions(root);
       /* parseBeanDefinitions(root);*/
    }

    /**
     * Register each bean definition within the given root element.
     *
     * @param root the DOM root element of the document
     * @return
     */
    protected int doRegisterBeanDefinitions(Element root) {
        int counter = 0;
        //获取子节点
        NodeList childNodes = root.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            /*xml的bean配置节点*/
            Node node = childNodes.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                //生成BeanDefinition
                processBeanDefinition(ele);
                counter++;
            }
        }
        return counter;
    }

    protected void processBeanDefinition(Element ele) {
               /*bean的名称*/
        String beanName = ele.getAttribute("id");
        /*bean的类路径*/
        String className = ele.getAttribute("class");
        /*bean的类型*/
        String beanScopeStr = ele.getAttribute("scope");
    /*    if (beanScopeStr.length() < 0) {
            beanScopeStr = "singletion";
        }*/
        BeanScope beanScope = StringUtils.convertStr2Enum(beanScopeStr);
        Class<?> clazz = null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        /*生成指定的*/
        BeanDefinition beanDefinition = new BeanDefinition(beanScope, beanName, clazz);
        /*beanDefinition获取属性*/
        processProperty(ele, beanDefinition);
        try {
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        } catch (BeanDefinitionStoreException e) {
            e.printStackTrace();
        }
    }

    private void processProperty(Element ele, BeanDefinition beanDefinition) {
        /*属性值节点分析*/
        NodeList propertyNodeList = ele.getElementsByTagName("property");
        for (int i = 0; i < propertyNodeList.getLength(); i++) {
            Node node = propertyNodeList.item(i);
            if (node instanceof Element) {
                Element propertyEle = (Element) node;//属性节点
                String name = propertyEle.getAttribute("name");
                String value = propertyEle.getAttribute("value");
                if (value != null && value.length() > 0) {
                    /*给属性赋值*/
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, value));
                } else {
                    String ref = propertyEle.getAttribute("ref");
                    if (ref == null || ref.length() == 0) {
                        try {
                            throw new IllegalArgumentException("Configuration problem:<property> element for property'" + name + "'must specified a ref or value");
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        }
                    }
                    BeanReference beanReference = new BeanReference(ref);
                    beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));
                }

            }
        }
    }
}
